package com.zzw.springboot.util;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * Redisson分布式锁工具类
 * 
 * 与RedisLockUtil相比，此工具类基于Redisson实现，具有以下优势：
 * 1. 支持看门狗（WatchDog）机制，自动续期，解决业务执行时间超过锁过期时间的问题
 * 2. 支持可重入锁，同一线程可多次获取同一把锁
 * 3. 提供更丰富的锁类型：公平锁、读写锁、联锁、红锁等
 * 4. 支持异步API
 */
@Component
public class RedissonLockUtil {

    @Autowired
    private RedissonClient redissonClient;
    
    // 锁前缀
    private static final String LOCK_PREFIX = "lock:";
    
    /**
     * 获取锁（不设置超时，依赖看门狗机制自动续期）
     * 
     * @param lockKey 锁键
     * @return 是否获取成功
     */
    public boolean lock(String lockKey) {
        String key = LOCK_PREFIX + lockKey;
        RLock lock = redissonClient.getLock(key);
        // 加锁，不设置超时时间，依赖看门狗机制自动续期
        lock.lock();
        return true;
    }
    
    /**
     * 获取锁（设置超时，到期自动释放）
     * 注意：设置了超时时间的锁不会启用看门狗机制
     * 
     * @param lockKey 锁键
     * @param timeout 锁超时时间
     * @param unit    时间单位
     * @return 是否获取成功
     */
    public boolean lock(String lockKey, long timeout, TimeUnit unit) {
        String key = LOCK_PREFIX + lockKey;
        RLock lock = redissonClient.getLock(key);
        lock.lock(timeout, unit);
        return true;
    }
    
    /**
     * 尝试获取锁（带超时等待）
     * 
     * @param lockKey   锁键
     * @param waitTime  等待时间
     * @param leaseTime 持有锁时间，为-1时使用看门狗机制
     * @param unit      时间单位
     * @return 是否获取成功
     */
    public boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
        try {
            String key = LOCK_PREFIX + lockKey;
            RLock lock = redissonClient.getLock(key);
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
    
    /**
     * 释放锁
     * 
     * @param lockKey 锁键
     */
    public void unlock(String lockKey) {
        String key = LOCK_PREFIX + lockKey;
        RLock lock = redissonClient.getLock(key);
        // 检查当前线程是否持有锁
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
    
    /**
     * 判断锁是否被持有
     * 
     * @param lockKey 锁键
     * @return 是否被持有
     */
    public boolean isLocked(String lockKey) {
        String key = LOCK_PREFIX + lockKey;
        RLock lock = redissonClient.getLock(key);
        return lock.isLocked();
    }
} 